----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    09:29:14 07/23/2011 
-- Design Name: 
-- Module Name:    rx_uart - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity rx_uart is
	 generic(
				BAUDCLOCK: integer := 15  --number of clocks between ticks - 1  --15 115200  --3 460800
				);
    Port (  RX_IN : in  STD_LOGIC;
            FIFO_18_BIT_OUT : out  STD_LOGIC_VECTOR (17 downto 0):= (others=> '0'); -- use fifo 
            CLOCK_IN : in  STD_LOGIC;  -- ~29.53MHZ clock
			READ_MESSAGE_IN : in std_logic;   -- be high for entire message being read in.
			MESSAGE_READY_OUT : out std_logic;  --goes high signaling a message in queue
			TICKSIGNAL_OUT : out STD_LOGIC;     --signal controls uart 16 ticks per bit
			VALID_OUT : out STD_LOGIC;			--when data is valid to read from message fifo
            RESET_IN : in  STD_LOGIC);			--Reset input
end rx_uart;

architecture Behavioral of rx_uart is

COMPONENT fifo_generator_v9_1
	PORT(
		clk : IN STD_LOGIC;
		rst : IN STD_LOGIC;
		din : IN STD_LOGIC_VECTOR(17 DOWNTO 0);
		wr_en : IN STD_LOGIC;
		rd_en : IN STD_LOGIC;
		dout : OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
		full : OUT STD_LOGIC;  --active high
		overflow : OUT STD_LOGIC; --active high
		empty : OUT STD_LOGIC; --active high
		valid : OUT std_logic; -- active high
		underflow : OUT STD_LOGIC --active high
		);
	END COMPONENT;

--constants
constant PROTOCOL1 : std_logic_vector(7 downto 0) := x"AA";
constant PROTOCOL2 : std_logic_vector(7 downto 0) := x"BB";
constant FOOTER1 : std_logic_vector(7 downto 0) := x"CC";
constant FOOTER2 : std_logic_vector(7 downto 0) := x"DD";
constant MID1 : std_logic_vector(15 downto 0) := x"0001";
	
--Baud Generator	
signal tick_sig : std_logic := '0';
signal baud_cnt : std_logic_vector(5 downto 0) := (others => '0');
signal cnt : std_logic_vector(7 downto 0) := (others => '0');

--RX Process
signal rx_reg	: std_logic_vector(7 downto 0) := (others => '0');
signal cnt_en : std_logic := '0';
signal rx_out : std_logic_vector(7 downto 0);
signal reset_cnt : std_logic := '0';
signal byte_ready :std_logic := '0';


--fifo component signals
signal fifo_18_sig : std_logic_vector(17 downto 0) := "000000000000000000";
signal wr_en: std_logic := '0';
signal rd_en : std_logic := '0';
signal rx_fifo_data_in :std_logic_vector(17 downto 0) := "000000000000000000";
signal msgs_in_queue : std_logic_vector(7 downto 0) := "00000000";
signal valid_sig : std_logic := '0';

--fifo process
signal fifo_start : std_logic := '0';
signal fifo_end : std_logic := '0';
signal rx_protocol1_match : std_logic := '0';
signal rx_protocol2_match : std_logic := '0';
signal rx_footer1_match : std_logic := '0';
signal rx_footer2_match : std_logic := '0';
signal byte_upper : std_logic := '0';
signal byte_lower : std_logic := '0';
signal latch_byte_count : std_logic := '0';
signal rx_byte_count_en : std_logic := '0';
signal rx_message_end : std_logic := '0';
signal rx_byte_count : std_logic_vector(15 downto 0) := x"FFFF";
--signal rx_error : std_logic := '0';
signal rx_byte_count_reset : std_logic := '0';
signal byte_ready_delay : std_logic := '0';
signal latch_byte_count_delay : std_logic := '0';
signal read_msg_sig : std_logic := '0';
signal read_msg_sig_delay : std_logic := '0';
signal receive_pulse : std_logic := '0';


--rx state machine
type RXState is (
		RXIdle,
		RXProtocol,
		RXMid1,
		RXMid2,
		RXByte1,
		RXByte2,
		RXUpper,
		RXLower,
		RXFooter1,
		RXFooter2
		);

signal RXCur :	RXState := RXIdle;	

	
begin

Inst_fifo_generator_v9_1: fifo_generator_v9_1 PORT MAP(
		clk =>CLOCK_IN,
		rst => RESET_IN,
		din => rx_fifo_data_in,
		wr_en => wr_en,
		rd_en => rd_en,
		dout => fifo_18_sig,
		full => open,
		overflow => open,
		empty => open, 
		valid => valid_sig,
		underflow => open
	);

TICKSIGNAL_OUT <= tick_sig; --tick signal also used by tx_uart 16 ticks per character
FIFO_18_BIT_OUT <= fifo_18_sig; --fifo output
VALID_OUT <= valid_sig; --data valid from fifo output

--Baud Generator
--Generates a tick every 1/16 of baud Rate
baudgenerator : process(CLOCK_IN)
begin

	if(rising_edge(CLOCK_IN)) then
		tick_sig <= '0';
		baud_cnt <= std_logic_vector( unsigned(baud_cnt) + 1 );	
		
		if(unsigned(baud_cnt) = BAUDCLOCK) then
			baud_cnt <= (others => '0');
			tick_sig <= '1';
		end if;
		
		if(RESET_IN = '1') then
			tick_sig <= '0';
			baud_cnt <= (others => '0');
		end if;
	end if;
end process;

--rx process
rx_process : process(CLOCK_IN)
begin

	
	if(rising_edge(CLOCK_IN)) then
		
		reset_cnt <= '0';
		byte_ready <= '0';
		
		--wait for incoming start bit of '0'
		--enable counter to find middle of uart bit
		if(RX_IN = '0' and cnt_en = '0') then
			cnt_en <= '1';
		end if;
		
		--There are 16 ticks per bit 
		--find middle bit at count = 7
		--will sample signal in the middle
		case cnt is
			when x"07" =>
				if RX_IN /= '0' then
					cnt_en <= '0';
				end if;
			when x"17" =>
				rx_reg(0) <= RX_IN;
			when x"27" =>
				rx_reg(1) <= RX_IN;
			when x"37" =>
				rx_reg(2) <= RX_IN;
			when x"47" =>
				rx_reg(3) <= RX_IN;
			when x"57" =>
				rx_reg(4) <= RX_IN;
			when x"67" =>
				rx_reg(5) <= RX_IN;
			when x"77" =>
				rx_reg(6) <= RX_IN;
			when x"87" =>
				rx_reg(7) <= RX_IN;
			when x"97" =>
				cnt_en <= '0';
				reset_cnt <= '1';
				if RX_IN = '1' then
					rx_out <= rx_reg;
					byte_ready <= '1';
				end if;
			when others =>
				null;
		end case;
			
		if(tick_sig = '1' and cnt_en = '1') then
			cnt <= std_logic_vector( unsigned(cnt) + 1 );
		end if;
		
		if(reset_cnt = '1') then
			cnt <= (others => '0');
		end if;
		
		if(RESET_IN = '1') then
			cnt <= (others => '0');
			rx_reg	<= (others => '0');
			cnt_en <= '0'; 
			rx_out <= (others => '0');
		end if;		
	end if;
end process;

MESSAGE_READY_OUT <= '1' when (msgs_in_queue /= x"00") else '0';

rd_en <= READ_MESSAGE_IN;
--Process for storing rx byte into fifo
process (CLOCK_IN)
	begin
	
	if(rising_edge(CLOCK_IN)) then
		wr_en <= '0';
		rx_protocol1_match <= '0';
		rx_protocol2_match <= '0';
		rx_footer1_match <= '0';
		rx_footer2_match <= '0';
		byte_upper <= '0';
		byte_lower <= '0';
		latch_byte_count <= '0';
		rx_byte_count_en <= '0';
		rx_message_end <= '0';
		--rx_error <= '0';
		rx_byte_count_reset <= '0';
		fifo_start <= '0';
		fifo_end <= '0';
		rx_fifo_data_in(17) <= '0';
		rx_fifo_data_in(16) <= '0';
		receive_pulse <= '0';
		
		byte_ready_delay <= byte_ready;  --delay for latched signals
		latch_byte_count_delay <= latch_byte_count;
		read_msg_sig <= READ_MESSAGE_IN;
		read_msg_sig_delay <= read_msg_sig;
		
		if(msgs_in_queue /= x"00" AND read_msg_sig_delay = '0' AND read_msg_sig = '1') then
			msgs_in_queue <= std_logic_vector(unsigned(msgs_in_queue) - 1);
		end if;
		
		if(byte_ready = '1' and byte_ready_delay = '0') then
			receive_pulse <= '1';
		end if;
		
		--byte to word process
		if(byte_ready = '1' AND rx_out = PROTOCOL1 ) then
			rx_protocol1_match <= '1';
		end if;
		
		if(byte_ready = '1' AND rx_out = PROTOCOL2 ) then
			rx_protocol2_match <= '1';
		end if;
		
		if(byte_ready = '1' AND rx_out = FOOTER1 ) then
			rx_footer1_match <= '1';
		end if;
		
		if(byte_ready = '1' AND rx_out = FOOTER2 ) then
			rx_footer2_match <= '1';
		end if;
		
		if(byte_upper = '1') then
			rx_fifo_data_in(15 downto 8) <=  rx_out;
			
		end if;
		
		if(byte_lower = '1') then
			rx_fifo_data_in(7 downto 0) <=  rx_out;
			wr_en <= '1';
			if(fifo_start = '1') then
				rx_fifo_data_in(16) <= '1';
			end if;
			if(fifo_end = '1') then
				rx_fifo_data_in(17) <= '1';
			end if;
		end if;
		
		if(RESET_IN = '1') then
			RXCur <= RXIdle;
			msgs_in_queue <= x"00";
			rx_protocol1_match <= '0';
			rx_byte_count <= x"FFFF";
		end if;
		
		if(latch_byte_count_delay = '1') then
			rx_byte_count <= std_logic_vector(unsigned(rx_fifo_data_in(15 downto 0)) - 5);
		end if;
		
		if(rx_byte_count_en = '1') then
			rx_byte_count <= std_logic_vector(unsigned(rx_byte_count(15 downto 0)) - 1);
		end if;
		
		if(rx_byte_count = x"0000") then
			rx_message_end <= '1';
		end if;
		
		if(rx_byte_count_reset = '1') then
			rx_byte_count <= x"FFFF";
		end if;
		
		if(receive_pulse = '1') then
			case RXCur is
				when RXIdle =>
					RXCur <= RXProtocol;
					if(rx_protocol1_match = '0') then
						RXCur <= RXIdle;
						--rx_error <= '1';
					end if;
				when RXProtocol =>
					RXCur <= RXMid1;
					if(rx_protocol2_match = '0') then
						RXCur <= RXIdle;
						--rx_error <= '1';
					end if;
				when RXMid1 =>
					RXCur <= RXMid2;
					byte_upper <= '1';
				when RXMid2 =>
					RXCur <= RXByte1;
					byte_lower <= '1';
					fifo_start <= '1';
				when RXByte1 =>
					RXCur <= RXByte2;
					byte_upper <= '1';
				when RXByte2 =>
					RXCur <= RXUpper;
					byte_lower <= '1';
					latch_byte_count <= '1';
				when RXUpper =>
					RXCur <= RXLower;
					byte_upper <= '1';
					rx_byte_count_en <= '1';
				when RXLower =>
					RXCur <= RXUpper;
					byte_lower <= '1';
					rx_byte_count_en <= '1';
					if(rx_message_end = '1') then
						rx_byte_count_en <= '0';
						rx_byte_count_reset <= '1';
						rx_fifo_data_in(1) <= '1';
						RXCur <= RXFooter1;
						fifo_end <= '1';
					end if;
				when RXFooter1 =>
					RXCur <= RXFooter2;
					if(rx_footer1_match = '0') then
						RXCur <= RXIdle;
						--rx_error <= '1';
					end if;
				when RXFooter2 =>
					
					RXCur <= RXIdle;
					msgs_in_queue <= std_logic_vector(unsigned(msgs_in_queue) + 1);
					if(rx_footer2_match = '0') then
						--rx_error <= '1';
					end if;
				when others =>
					RXCur <= RXIdle;
			end case;			
		end if;
	end if;
		
end process;

end Behavioral;

